package com.net.xpay.core.service.impl.safePay;

import com.google.common.base.Strings;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserProfile;
import com.net.xpay.common.domain.notify.SafePayBatchNotifyRecord;
import com.net.xpay.common.enums.config.CommonSysConfigKey;
import com.net.xpay.common.enums.notify.NotifyStatus;
import com.net.xpay.common.enums.user.CommissionMode;
import com.net.xpay.common.enums.user.ServicePayMode;
import com.net.xpay.common.helper.CommonSysConfigHelper;
import com.net.xpay.common.helper.NoticeHelper;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserProfileManager;
import com.net.xpay.core.constant.TransBizTypeConstant;
import com.net.xpay.core.dto.SafePayBatchDto;
import com.net.xpay.core.dto.SafePayOrderDto;
import com.net.xpay.core.service.safePay.CollectionSafePayService;
import com.net.xpay.core.service.safePay.SafePayInnerService;
import com.net.common.annotation.WriteTransactional;
import com.net.common.util.SerializationUtil;
import com.net.xpay.common.manager.notify.SafePayBatchNotifyRecordManager;
import com.net.xpay.common.manager.partner.PartnerCodeManager;
import com.net.xpay.common.service.PartnerWithdrawService;
import com.net.xpay.core.domain.AccountDetail;
import com.net.xpay.core.domain.UserAccount;
import com.net.xpay.core.domain.safePay.SafePayBatch;
import com.net.xpay.core.domain.safePay.SafePayOrder;
import com.net.xpay.core.dto.*;
import com.net.xpay.core.enums.AccountBillType;
import com.net.xpay.core.enums.PayeeType;
import com.net.xpay.core.enums.SafePayBatchStatus;
import com.net.xpay.core.helper.AccountDetailHelper;
import com.net.xpay.core.manager.AccountDetailManager;
import com.net.xpay.core.manager.UserAccountManager;
import com.net.xpay.core.manager.safePay.SafePayBatchManager;
import com.net.xpay.core.manager.safePay.SafePayOrderManager;
import com.net.xpay.core.service.AccountService;
import com.net.xpay.core.utils.BeanCopierUtil;
import lombok.extern.slf4j.Slf4j;;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class SafePayInnerServiceImpl implements SafePayInnerService {

    @Autowired
    private AccountService accountService;

    @Autowired
    private UserAccountManager userAccountManager;

    @Autowired
    private AccountDetailHelper accountDetailHelper;

    @Autowired
    private NoticeHelper noticeHelper;

    @Autowired
    private AccountDetailManager accountDetailManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private SafePayBatchManager safePayBatchManager;

    @Autowired
    private PartnerCodeManager partnerCodeManager;

    @Autowired
    private UserProfileManager userProfileManager;

    @Autowired
    private SafePayBatchNotifyRecordManager safePayBatchNotifyRecordManager;

    @Autowired
    private SafePayOrderManager safePayOrderManager;

    @Autowired
    private CollectionSafePayService collectionSafePayService;

    @Autowired
    private PartnerWithdrawService partnerWithdrawService;

    @Autowired
    private CommonSysConfigHelper commonSysConfigHelper;



    @WriteTransactional
    @Override
    public void settleBatchBenefit(SafePayBatch batch) {
        UserAccount userAccount = userAccountManager.getByIdWithLock(batch.getUserId());
        User user = userManager.getById(batch.getUserId());
        //处理退款金额 分
        long refund = processRefund(user, userAccount, batch);
        batch.setRefund(refund);
        batch.setFinalServicePrice(batch.getServicePrice() - batch.getRefund());

        //计算收益
        calBenefit(batch, user);

        if (batch.getSuccessCount().equals(batch.getTotalCount())) {
            batch.setStatus(SafePayBatchStatus.SUCCESS);
        } else if (batch.getFailCount().equals(batch.getTotalCount())) {
            batch.setStatus(SafePayBatchStatus.FAIL);
        } else {
            batch.setStatus(SafePayBatchStatus.PART_SUCCESS);
        }

        batch.setEndTime(LocalDateTime.now());
        safePayBatchManager.updateByPrimaryKeyWithVersion(batch);

        //推送消息
        processNotifyRecord(user, batch);

        //处理关联业务
        processRelatedBusiness(user, batch);
    }

    private void processRelatedBusiness(User user, SafePayBatch batch) {
        //安全付收集到卡
        if (batch.getImportBatchNo().startsWith(TransBizTypeConstant.CB_SP)) {
            collectionSafePayService.updateCollectionSafePayBatch(user, batch);
        } else if (batch.getImportBatchNo().startsWith(TransBizTypeConstant.PW)) {
            partnerWithdrawService.updatePartnerWithdrawBatchResultBySafePay(user, batch);
        }
    }


    private void processNotifyRecord(User user, SafePayBatch batch) {
        UserProfile userProfile = userProfileManager.getById(user.getId());
        if (!Boolean.TRUE.equals(batch.getNeedNotify())) {
            return;
        }
        SafePayBatchNotifyRecord notifyRecord = safePayBatchNotifyRecordManager.getBySafePayBatchId(batch.getId());
        if (notifyRecord != null && notifyRecord.getStatus() == NotifyStatus.INIT) {
            //新链路 预存了notifyUrl
            notifyRecord.setStatus(NotifyStatus.WAIT);
            notifyRecord.setNextNotifyTime(LocalDateTime.now());

            SafePayBatchDto dto = new SafePayBatchDto();
            BeanCopierUtil.copy(batch, dto);
            List<SafePayOrder> orders = safePayOrderManager.listByBatchId(user.getId(), batch.getId());
            List<SafePayOrderDto> orderDtos = BeanCopierUtil.batchCopy(SafePayOrder.class, SafePayOrderDto.class, orders);
            dto.setOrders(orderDtos);
            notifyRecord.setNotifyContent(SerializationUtil.obj2String(dto));
            safePayBatchNotifyRecordManager.update(notifyRecord);
            return;
        }

        //老链路 兼容以前的数据 后面新的订单都不会执行下面的代码
        if (Strings.isNullOrEmpty(userProfile.getSafePayNotifyUrl())) {
            return;
        }

        SafePayBatchNotifyRecord record = SafePayBatchNotifyRecord.getInstance();
        record.setUserId(batch.getUserId());
        record.setImportBatchNo(batch.getImportBatchNo());
        record.setSafePayBatchId(batch.getId());
        record.setStatus(NotifyStatus.WAIT);
        record.setNotifyCount(0);
        record.setNextNotifyTime(LocalDateTime.now());

        SafePayBatchDto dto = new SafePayBatchDto();
        BeanCopierUtil.copy(batch, dto);
        List<SafePayOrder> orders = safePayOrderManager.listByBatchId(user.getId(), batch.getId());
        List<SafePayOrderDto> orderDtos = BeanCopierUtil.batchCopy(SafePayOrder.class, SafePayOrderDto.class, orders);
        dto.setOrders(orderDtos);
        record.setNotifyContent(SerializationUtil.obj2String(dto));

        safePayBatchNotifyRecordManager.save(record);
    }

    public void calBenefit(SafePayBatch batch, User user) {
        log.info("calBenefit safe pay batch={}", SerializationUtil.obj2String(batch));
        if (batch.getFree()) {
            return;
        }
        if (batch.getFinalServicePrice() <= 0L) {
            return;
        }

        if (batch.getPartnerId() == null) {
            batch.setBenefitRatio(new BigDecimal(0));
            batch.setFatherBenefitRatio(new BigDecimal(0));
            batch.setUnitPartnerBenefit(0L);
            batch.setUnitFatherPartnerBenefit(0L);
            batch.setTotalPartnerBenefit(0L);
            batch.setTotalFatherPartnerBenefit(0L);
            batch.setTotalPlatformBenefit(batch.getFinalServicePrice());
            return;
        }

        if (batch.getFatherPartnerId() == null) {
            //一级合伙人商户走原来逻辑不改动
            doCalLevel1PartnerBenefit(batch, user);
        } else {
            //二级合伙人商户
            doCalLevel2PartnerBenefit(batch, user);
        }


    }

    private void doCalLevel2PartnerBenefit(SafePayBatch batch, User user) {
        batch.setBenefitRatio(batch.getBenefitRatio() != null ? batch.getBenefitRatio() : user.getBenefitRatio());
        batch.setFatherBenefitRatio(batch.getFatherBenefitRatio() != null ? batch.getFatherBenefitRatio() : user.getFatherBenefitRatio());
        batch.setUnitPartnerBenefit(batch.getUnitPartnerBenefit() != null ? batch.getUnitPartnerBenefit() : user.getPartnerBenefit());
        batch.setUnitFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() != null ? batch.getUnitFatherPartnerBenefit() : user.getFatherPartnerBenefit());

        BigDecimal ratio = new BigDecimal("0.0005");
        //到卡有手续费
        String bankRatio = commonSysConfigHelper.getString(CommonSysConfigKey.SINGE_TRANS_BANK_COST_RATIO);
        if (!Strings.isNullOrEmpty(bankRatio)) {
            ratio = new BigDecimal(bankRatio);
        }

        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            batch.setTotalPartnerBenefit(batch.getUnitPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalPlatformBenefit(batch.getSuccessCount() * batch.getServiceUnitPrice() - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
        } else {
            long benefit = batch.getFinalServicePrice();

            if (CommissionMode.COST_MODE.equals(batch.getCommissionMode())) {
                //先分二级合伙人
                BigDecimal partnerServiceRatio = batch.getServiceRatio().subtract(batch.getCostServiceRatio());
                batch.setTotalPartnerBenefit(batch.getSuccessAmount().multiply(partnerServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());

                //再分上级合伙人
                long leftBenefit = benefit - batch.getTotalPartnerBenefit();

                if (user.getFatherCommissionMode() == CommissionMode.FIXED_MODE) {
                    //固定比例
                    //充值成本
                    long chargeCost = new BigDecimal(leftBenefit).multiply(new BigDecimal("0.006")).multiply(user.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                    if (chargeCost == 0L) {
                        chargeCost = 1L;//最少一分钱
                    }
                    //到卡成本
                    long bankCost = 0L;
                    if (batch.getType() == PayeeType.BANK) {
                        bankCost = batch.getSuccessAmount().multiply(ratio).multiply(new BigDecimal(100)).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                    }
                    log.info("doCalLevel2PartnerBenefit bankCost={}|chargeCost={}|importBatchNo={}", bankCost, chargeCost, batch.getImportBatchNo());
                    batch.setTotalFatherPartnerBenefit(new BigDecimal(leftBenefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost - bankCost);
                    if (batch.getTotalFatherPartnerBenefit() < 0L) {
                        log.warn("doCalLevel2PartnerBenefit partner benefit < 0|importBatchNo={}|cal benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                        batch.setTotalFatherPartnerBenefit(0L);
                    }
                } else if (user.getFatherCommissionMode() == CommissionMode.COST_MODE) {
                    BigDecimal fatherServiceRatio = user.getFatherServiceRatio() ;
                    batch.setTotalFatherPartnerBenefit(batch.getSuccessAmount().multiply(fatherServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());
                }

                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            } else {
                long chargeCost = new BigDecimal(benefit).multiply(new BigDecimal("0.006")).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                //到卡成本
                long bankCost = 0L;
                if (batch.getType() == PayeeType.BANK) {
                    bankCost = batch.getSuccessAmount().multiply(ratio).multiply(new BigDecimal(100)).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                }
                log.info("doCalLevel2PartnerBenefit bankCost={}|chargeCost={}|importBatchNo={}", bankCost, chargeCost, batch.getImportBatchNo());
                batch.setTotalPartnerBenefit(new BigDecimal(benefit).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost - bankCost);
                if (batch.getTotalPartnerBenefit() < 0L) {
                    log.warn("doCalLevel2PartnerBenefit partner benefit < 0|importBatchNo={}|cal benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                    batch.setTotalPartnerBenefit(0L);
                }

                //再分上级合伙人
                long leftBenefit = benefit - batch.getTotalPartnerBenefit();
                chargeCost = new BigDecimal(leftBenefit).multiply(new BigDecimal("0.006")).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                //到卡成本
                long level1BankCost = 0L;
                if (batch.getType() == PayeeType.BANK) {
                    long leftBankCost = batch.getSuccessAmount().multiply(ratio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).longValue() - bankCost;
                    level1BankCost = new BigDecimal(leftBankCost).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                }
                log.info("doCalLevel2PartnerBenefit bankCost={}|level1BankCost={}|importBatchNo={}", level1BankCost, chargeCost, batch.getImportBatchNo());
                batch.setTotalFatherPartnerBenefit(new BigDecimal(leftBenefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost - level1BankCost);
                if (batch.getTotalFatherPartnerBenefit() < 0L) {
                    log.warn("doCalLevel2PartnerBenefit partner benefit < 0|importBatchNo={}|cal benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                    batch.setTotalFatherPartnerBenefit(0L);
                }

                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            }
        }

        if (batch.getTotalPlatformBenefit() < 0L) {
            log.error("safe pay doCalLevel2PartnerBenefit totalPlatformBenefit <= 0|batch={}", SerializationUtil.obj2String(batch.getTotalPlatformBenefit()));
            noticeHelper.sendSystemMonitorNotice("safe pay doCalLevel2PartnerBenefit 严重错误 平台收益小于0 请赶快处理！|batchId=" + batch.getId(), "text");
        }
    }

    private void doCalLevel1PartnerBenefit(SafePayBatch batch, User user) {
        batch.setBenefitRatio(batch.getBenefitRatio() != null ? batch.getBenefitRatio() : user.getBenefitRatio());
        batch.setFatherBenefitRatio(batch.getFatherBenefitRatio() != null ? batch.getFatherBenefitRatio() : user.getFatherBenefitRatio());
        batch.setUnitPartnerBenefit(batch.getUnitPartnerBenefit() != null ? batch.getUnitPartnerBenefit() : user.getPartnerBenefit());
        batch.setUnitFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() != null ? batch.getUnitFatherPartnerBenefit() : user.getFatherPartnerBenefit());

        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            batch.setTotalPartnerBenefit(batch.getUnitPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalPlatformBenefit(batch.getSuccessCount() * batch.getServiceUnitPrice() - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
        } else {
            long benefit = batch.getFinalServicePrice();

            if (CommissionMode.COST_MODE.equals(batch.getCommissionMode())) {
                //先算合伙人收益 再算平台收益
                BigDecimal partnerServiceRatio = batch.getServiceRatio().subtract(batch.getCostServiceRatio());
                batch.setTotalPartnerBenefit(batch.getSuccessAmount().multiply(partnerServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());
                batch.setTotalFatherPartnerBenefit(0L);
                if (batch.getTotalPartnerBenefit() > benefit) {
                    noticeHelper.sendSystemMonitorNotice("safe pay calBenefit 平台收益计算可能存在问题 请观察改记录！|batchId=" + batch.getId(), "text");
                    batch.setTotalPartnerBenefit(benefit);
                }
                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit());
            } else if (CommissionMode.STAT_MODE.equals(batch.getCommissionMode())) {
                batch.setTotalPlatformBenefit(benefit);
                batch.setTotalPartnerBenefit(0L);
                batch.setTotalFatherPartnerBenefit(0L);
            } else {
                long chargeCost = new BigDecimal(benefit).multiply(new BigDecimal("0.006")).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                //到卡成本
                long bankCost = 0L;
                if (batch.getType() == PayeeType.BANK) {
                    BigDecimal ratio = new BigDecimal("0.0005");
                    //到卡有手续费
                    String bankRatio = commonSysConfigHelper.getString(CommonSysConfigKey.SINGE_TRANS_BANK_COST_RATIO);
                    if (!Strings.isNullOrEmpty(bankRatio)) {
                        ratio = new BigDecimal(bankRatio);
                    }
                    bankCost = batch.getSuccessAmount().multiply(ratio).multiply(new BigDecimal(100)).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                }
                log.info("calBenefit bankCost={}|chargeCost={}|importBatchNo={}", bankCost, chargeCost, batch.getImportBatchNo());
                batch.setTotalPartnerBenefit(new BigDecimal(benefit).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost - bankCost);
                if (batch.getTotalPartnerBenefit() < 0L) {
                    log.warn("calBenefit partner benefit < 0|importBatchNo={}|cal benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                    batch.setTotalPartnerBenefit(0L);
                }
                batch.setTotalFatherPartnerBenefit(new BigDecimal(benefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue());
                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            }
        }

        if (batch.getTotalPlatformBenefit() < 0L && batch.getServiceUnitPrice() != 0L && batch.getSuccessCount() != 0L) {
            log.error("safe pay calBenefit totalPlatformBenefit <= 0|batch={}", SerializationUtil.obj2String(batch.getTotalPlatformBenefit()));
            noticeHelper.sendSystemMonitorNotice("safe pay calBenefit 严重错误 平台收益小于0 请赶快处理！|batchId=" + batch.getId(), "text");
        }
    }

    private long processRefund(User user, UserAccount userAccount, SafePayBatch batch) {
        log.info("processRefund safe batch={}", SerializationUtil.obj2String(batch));
        //免费批次不退款
        if (batch.getFree() || batch.getServicePrice() == 0L) {
            return 0L;
        }
        if (batch.getFailCount() == null || batch.getFailCount() == 0L) {
            return 0L;
        }
        //查询历史有没有退过
        AccountDetail selected = accountDetailManager.findByRelatedId(user.getId(), batch.getId(), AccountBillType.SAFE_PAY_TRANS_SERVICE_PRICE_REFUND);
        if (selected != null) {
            log.warn("account detail exist safe batch={}", SerializationUtil.obj2String(batch));
            return selected.getChange();
        }

        long refund;
        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            refund = batch.getFailCount() * batch.getServiceUnitPrice();
        } else {
            refund = batch.getFailedAmount().multiply(batch.getServiceRatio()).multiply(new BigDecimal(100)).setScale(0, RoundingMode.UP).longValue();
        }

        AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), batch.getId());
        accountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.SAFE_PAY_TRANS_SERVICE_PRICE_REFUND, refund, "安全付批量转账失败订单退款");
        accountService.onPay(user, userAccount, accountDetail);

        return refund;
    }
}
